﻿namespace Voxel2Unity
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using UnityEngine;

    public class VoxelMesh
    {
        private VoxData MainVoxelData;
        private int MaxFacesInOneMesh = 0x3f48;
        private Vector3 Pivot = new Vector3(0.5f, 0f, 0.5f);
        private float Scale = 0.01f;
        private int SizeX;
        private int SizeY;
        private int SizeZ;
        private List<VoxelFace> VoxelFaces = new List<VoxelFace>();
        private Voxel[,,] Voxels;

        private void CreateMesh(VoxData voxelData, ref Mesh[] meshs, ref Texture2D aimTexture)
        {
            int num = (this.VoxelFaces.Count / this.MaxFacesInOneMesh) + 1;
            if ((this.VoxelFaces.Count % this.MaxFacesInOneMesh) == 0)
            {
                num--;
            }
            meshs = new Mesh[num];
            List<Dictionary<int, int>> list = new List<Dictionary<int, int>>();
            List<Texture2D[]> list2 = new List<Texture2D[]>();
            for (int i = 0; i < num; i++)
            {
                List<VoxelFace> list3 = new List<VoxelFace>(this.VoxelFaces.GetRange(i * this.MaxFacesInOneMesh, Mathf.Min(this.MaxFacesInOneMesh, this.VoxelFaces.Count - (i * this.MaxFacesInOneMesh))));
                List<Vector3> inVertices = new List<Vector3>();
                for (int m = 0; m < list3.Count; m++)
                {
                    VoxelFace face = list3[m];
                    Vector3[] points = face.Points;
                    for (int num4 = 0; num4 < 4; num4++)
                    {
                        points[num4] -= new Vector3(this.SizeX * this.Pivot.x, this.SizeZ * this.Pivot.y, this.SizeY * this.Pivot.z);
                        points[num4] = (Vector3) (points[num4] * this.Scale);
                    }
                    inVertices.AddRange(points);
                }
                List<int> triangles = new List<int>();
                for (int n = 0; n < list3.Count; n++)
                {
                    int[] numArray2;
                    VoxelFace face2 = list3[n];
                    if (face2.direction != Direction.Front)
                    {
                        VoxelFace face3 = list3[n];
                        if (face3.direction != Direction.Up)
                        {
                            VoxelFace face4 = list3[n];
                            if (face4.direction != Direction.Right)
                            {
                                goto Label_01EC;
                            }
                        }
                    }
                    int[] collection = new int[] { (n * 4) + 2, (n * 4) + 1, n * 4, (n * 4) + 3, (n * 4) + 1, (n * 4) + 2 };
                    triangles.AddRange(collection);
                    continue;
                Label_01EC:
                    numArray2 = new int[] { (n * 4) + 2, n * 4, (n * 4) + 1, (n * 4) + 3, (n * 4) + 2, (n * 4) + 1 };
                    triangles.AddRange(numArray2);
                }
                meshs[i] = new Mesh();
                meshs[i].Clear();
                meshs[i].SetVertices(inVertices);
                meshs[i].SetTriangles(triangles, 0);
                List<Texture2D> list6 = new List<Texture2D>();
                List<int> list7 = new List<int>();
                Dictionary<int, int> item = new Dictionary<int, int>();
                for (int num6 = 0; num6 < list3.Count; num6++)
                {
                    int num11;
                    int num12;
                    VoxelFace face23;
                    VoxelFace face24;
                    VoxelFace face5 = list3[num6];
                    int width = face5.Width + 2;
                    VoxelFace face6 = list3[num6];
                    int height = face6.Height + 2;
                    Color[] colors = new Color[width * height];
                    bool flag = true;
                    int num9 = -1;
                    int num10 = 0;
                    goto Label_060F;
                Label_02CD:
                    num11 = 0;
                    goto Label_05F0;
                Label_02D5:
                    num12 = 0;
                    VoxelFace face7 = list3[num6];
                    switch (face7.direction)
                    {
                        case Direction.Up:
                        case Direction.Down:
                        {
                            VoxelFace face14 = list3[num6];
                            VoxelFace face15 = list3[num6];
                            VoxelFace face16 = list3[num6];
                            num12 = this.Voxels[num10 + face14.VoxelX, num11 + face15.VoxelY, face16.VoxelZ].ColorIndex - 1;
                            break;
                        }
                        case Direction.Front:
                        case Direction.Back:
                        {
                            VoxelFace face8 = list3[num6];
                            VoxelFace face9 = list3[num6];
                            VoxelFace face10 = list3[num6];
                            num12 = this.Voxels[num10 + face8.VoxelX, face9.VoxelY, num11 + face10.VoxelZ].ColorIndex - 1;
                            break;
                        }
                        case Direction.Left:
                        case Direction.Right:
                        {
                            VoxelFace face11 = list3[num6];
                            VoxelFace face12 = list3[num6];
                            VoxelFace face13 = list3[num6];
                            num12 = this.Voxels[face11.VoxelX, num10 + face12.VoxelY, num11 + face13.VoxelZ].ColorIndex - 1;
                            break;
                        }
                    }
                    Color color = this.MainVoxelData.Palatte[num12];
                    colors[(((num11 + 1) * width) + num10) + 1] = color;
                    if (num9 == -1)
                    {
                        num9 = num12;
                    }
                    if (flag && (num9 != num12))
                    {
                        flag = false;
                    }
                    if (num10 == 0)
                    {
                        colors[((num11 + 1) * width) + num10] = color;
                    }
                    VoxelFace face17 = list3[num6];
                    if (num10 == (face17.Width - 1))
                    {
                        colors[(((num11 + 1) * width) + num10) + 2] = color;
                    }
                    if (num11 == 0)
                    {
                        colors[((num11 * width) + num10) + 1] = color;
                    }
                    VoxelFace face18 = list3[num6];
                    if (num11 == (face18.Height - 1))
                    {
                        colors[(((num11 + 2) * width) + num10) + 1] = color;
                    }
                    if ((num10 == 0) && (num11 == 0))
                    {
                        colors[0] = color;
                    }
                    if (num10 == 0)
                    {
                        VoxelFace face19 = list3[num6];
                        if (num11 == (face19.Height - 1))
                        {
                            colors[((num11 + 2) * width) + num10] = color;
                        }
                    }
                    VoxelFace face20 = list3[num6];
                    if ((num10 == (face20.Width - 1)) && (num11 == 0))
                    {
                        colors[((num11 * width) + num10) + 2] = color;
                    }
                    VoxelFace face21 = list3[num6];
                    if (num10 == (face21.Width - 1))
                    {
                        VoxelFace face22 = list3[num6];
                        if (num11 == (face22.Height - 1))
                        {
                            colors[(((num11 + 2) * width) + num10) + 2] = color;
                        }
                    }
                    num11++;
                Label_05F0:
                    face23 = list3[num6];
                    if (num11 < face23.Height)
                    {
                        goto Label_02D5;
                    }
                    num10++;
                Label_060F:
                    face24 = list3[num6];
                    if (num10 < face24.Width)
                    {
                        goto Label_02CD;
                    }
                    Texture2D textured = null;
                    int num13 = num6;
                    if (flag && (num9 > 0))
                    {
                        if (list7.Contains(num9))
                        {
                            num13 = list7.IndexOf(num9);
                        }
                        else
                        {
                            Color color2 = this.MainVoxelData.Palatte[num9];
                            textured = new Texture2D(3, 3, TextureFormat.ARGB32, false, false);
                            Color[] colorArray1 = new Color[] { color2, color2, color2, color2, color2, color2, color2, color2, color2 };
                            textured.SetPixels(colorArray1);
                            list6.Add(textured);
                            list7.Add(num9);
                            num13 = list6.Count - 1;
                        }
                    }
                    else
                    {
                        textured = new Texture2D(width, height, TextureFormat.ARGB32, false, false);
                        textured.SetPixels(colors);
                        list6.Add(textured);
                        list7.Add(-1);
                        num13 = list6.Count - 1;
                    }
                    if (textured != null)
                    {
                        textured.wrapMode = TextureWrapMode.Clamp;
                        textured.filterMode = FilterMode.Point;
                        textured.mipMapBias = 0f;
                        textured.Apply();
                    }
                    item.Add(num6, num13);
                }
                list2.Add(list6.ToArray());
                list6.Clear();
                list.Add(item);
            }
            aimTexture = new Texture2D(1, 1);
            List<Texture2D> list8 = new List<Texture2D>();
            for (int j = 0; j < list2.Count; j++)
            {
                list8.AddRange(list2[j]);
            }
            Rect[] rects = aimTexture.PackTextures(list8.ToArray(), 0);
            this.CutTexture(ref aimTexture, ref rects);
            List<Rect> list9 = new List<Rect>(rects);
            aimTexture.wrapMode = TextureWrapMode.Clamp;
            aimTexture.filterMode = FilterMode.Point;
            aimTexture.mipMapBias = 0f;
            aimTexture.Apply();
            int index = 0;
            for (int k = 0; k < num; k++)
            {
                List<VoxelFace> list10 = new List<VoxelFace>(this.VoxelFaces.GetRange(k * this.MaxFacesInOneMesh, Mathf.Min(this.MaxFacesInOneMesh, this.VoxelFaces.Count - (k * this.MaxFacesInOneMesh))));
                Rect[] rectArray2 = list9.GetRange(index, list2[k].Length).ToArray();
                float num17 = 1f / ((float) aimTexture.width);
                float num18 = 1f / ((float) aimTexture.height);
                Vector2[] vectorArray2 = new Vector2[list10.Count * 4];
                for (int num19 = 0; num19 < list10.Count; num19++)
                {
                    int num20 = list[k][num19];
                    if (num20 < rectArray2.Length)
                    {
                        vectorArray2[num19 * 4] = new Vector2(rectArray2[num20].xMin + num17, rectArray2[num20].yMin + num18);
                        vectorArray2[(num19 * 4) + 1] = new Vector2(rectArray2[num20].xMax - num17, rectArray2[num20].yMin + num18);
                        vectorArray2[(num19 * 4) + 2] = new Vector2(rectArray2[num20].xMin + num17, rectArray2[num20].yMax - num18);
                        vectorArray2[(num19 * 4) + 3] = new Vector2(rectArray2[num20].xMax - num17, rectArray2[num20].yMax - num18);
                    }
                }
                list[k].Clear();
                index += list2[k].Length;
                meshs[k].uv = vectorArray2;
                meshs[k].RecalculateNormals();
                meshs[k].Optimize();
            }
            list.Clear();
            list9.Clear();
        }

        private unsafe string CreateObj(Mesh[] meshs, string name)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("mtllib " + name + ".mtl\n");
            builder.Append("usemtl " + name + "\n");
            int num = 0;
            for (int i = 0; i < meshs.Length; i++)
            {
                Vector3[] vertices = meshs[i].vertices;
                Vector2[] uv = meshs[i].uv;
                int[] triangles = meshs[i].triangles;
                builder.Append("g " + name + "_" + i.ToString() + "_\n");
                foreach (Vector3 vector in vertices)
                {
                    builder.Append(string.Format("v {0} {1} {2}\n", -vector.x, vector.y, vector.z));
                }
                builder.Append("\n");
                Vector2[] vectorArray4 = uv;
                for (int j = 0; j < vectorArray4.Length; j++)
                {
                    Vector3 vector2 = *((Vector3*) &(vectorArray4[j]));
                    builder.Append(string.Format("vt {0} {1}\n", vector2.x, vector2.y));
                }
                builder.Append("\n");
                for (int k = 0; k < triangles.Length; k += 3)
                {
                    builder.Append(string.Format("f {2}/{2} {1}/{1} {0}/{0}\n", (triangles[k] + 1) + num, (triangles[k + 1] + 1) + num, (triangles[k + 2] + 1) + num));
                }
                builder.Append("\n");
                num += vertices.Length;
            }
            return builder.ToString();
        }

        public void CreateVoxelMesh(VoxData voxelData, float scale, Vector3 pivot, ref Texture2D texture, ref string objFile)
        {
            this.InitVoxels(voxelData, scale, pivot);
            this.FixVisible();
            this.Getfaces();
            Mesh[] meshs = null;
            this.CreateMesh(voxelData, ref meshs, ref texture);
            objFile = this.CreateObj(meshs, objFile);
        }

        public void CreateVoxelMesh(VoxData voxelData, float scale, Vector3 pivot, ref Mesh[] meshs, ref Texture2D texture)
        {
            this.InitVoxels(voxelData, scale, pivot);
            this.FixVisible();
            this.Getfaces();
            this.CreateMesh(voxelData, ref meshs, ref texture);
        }

        private void CutTexture(ref Texture2D texture, ref Rect[] rects)
        {
            if (texture != null)
            {
                float a = 0f;
                float num2 = 0f;
                for (int i = 0; i < rects.Length; i++)
                {
                    a = Mathf.Max(a, rects[i].xMax);
                    num2 = Mathf.Max(num2, rects[i].yMax);
                }
                for (int j = 0; j < rects.Length; j++)
                {
                    rects[j] = new Rect(rects[j].x / a, rects[j].y / num2, rects[j].width / a, rects[j].height / num2);
                }
                int width = Mathf.CeilToInt(texture.width * a);
                int height = Mathf.CeilToInt(texture.height * num2);
                Texture2D textured = new Texture2D(width, height, TextureFormat.ARGB32, false, false);
                textured.SetPixels(texture.GetPixels(0, 0, width, height));
                textured.wrapMode = TextureWrapMode.Clamp;
                textured.filterMode = FilterMode.Point;
                textured.mipMapBias = 0f;
                textured.Apply();
                texture = textured;
            }
        }

        private void FixVisible()
        {
            for (int i = 0; i < this.SizeX; i++)
            {
                for (int j = 0; j < this.SizeY; j++)
                {
                    for (int k = 0; k < this.SizeZ; k++)
                    {
                        if (this.Voxels[i, j, k].IsEmpty)
                        {
                            this.Voxels[i, j, k].IsVisible = true;
                        }
                        else
                        {
                            this.Voxels[i, j, k].VisibleLeft = (i <= 0) || this.Voxels[i - 1, j, k].IsEmpty;
                            this.Voxels[i, j, k].VisibleRight = (i >= (this.SizeX - 1)) || this.Voxels[i + 1, j, k].IsEmpty;
                            this.Voxels[i, j, k].VisibleFront = (j <= 0) || this.Voxels[i, j - 1, k].IsEmpty;
                            this.Voxels[i, j, k].VisibleBack = (j >= (this.SizeY - 1)) || this.Voxels[i, j + 1, k].IsEmpty;
                            this.Voxels[i, j, k].VisibleDown = (k <= 0) || this.Voxels[i, j, k - 1].IsEmpty;
                            this.Voxels[i, j, k].VisibleUp = (k >= (this.SizeZ - 1)) || this.Voxels[i, j, k + 1].IsEmpty;
                        }
                    }
                }
            }
        }

        private void Getfaces()
        {
            this.VoxelFaces.Clear();
            bool[,,,] flagArray = new bool[this.SizeX, this.SizeY, this.SizeZ, 6];
            int num = ((this.SizeX * this.SizeY) * this.SizeZ) * 6;
            while (num > 0)
            {
                for (int i = 0; i < this.SizeX; i++)
                {
                    for (int j = 0; j < this.SizeY; j++)
                    {
                        for (int k = 0; k < this.SizeZ; k++)
                        {
                            for (int m = 0; m < 6; m++)
                            {
                                if (!flagArray[i, j, k, m])
                                {
                                    if (this.Voxels[i, j, k].IsEmpty || !this.Voxels[i, j, k].Visible[m])
                                    {
                                        flagArray[i, j, k, m] = true;
                                        num--;
                                    }
                                    else
                                    {
                                        flagArray[i, j, k, m] = true;
                                        num--;
                                        int x = i;
                                        int y = j;
                                        int z = k;
                                        int num9 = i;
                                        int num10 = j;
                                        int num11 = k;
                                        for (int n = 0; n < 6; n++)
                                        {
                                            bool flag;
                                            int num13;
                                            if ((n / 2) != (m / 2))
                                            {
                                                flag = false;
                                                switch (((Direction) n))
                                                {
                                                    case Direction.Up:
                                                        num13 = num11;
                                                        goto Label_066E;

                                                    case Direction.Down:
                                                        num13 = z;
                                                        goto Label_0784;

                                                    case Direction.Front:
                                                        num13 = y;
                                                        goto Label_0224;

                                                    case Direction.Back:
                                                        num13 = num10;
                                                        goto Label_0333;

                                                    case Direction.Left:
                                                        num13 = x;
                                                        goto Label_0449;

                                                    case Direction.Right:
                                                        num13 = num9;
                                                        goto Label_0558;
                                                }
                                            }
                                            continue;
                                        Label_0132:
                                            num13--;
                                            for (int num14 = x; !flag && (num14 <= num9); num14++)
                                            {
                                                for (int num15 = z; num15 <= num11; num15++)
                                                {
                                                    if ((flagArray[num14, num13, num15, m] || this.Voxels[num14, num13, num15].IsEmpty) || !this.Voxels[num14, num13, num15].Visible[m])
                                                    {
                                                        flag = true;
                                                        break;
                                                    }
                                                }
                                            }
                                            if (!flag)
                                            {
                                                y = num13;
                                                for (int num16 = x; num16 <= num9; num16++)
                                                {
                                                    for (int num17 = z; num17 <= num11; num17++)
                                                    {
                                                        if (!flagArray[num16, num13, num17, m])
                                                        {
                                                            flagArray[num16, num13, num17, m] = true;
                                                            num--;
                                                        }
                                                    }
                                                }
                                            }
                                        Label_0224:
                                            if (!flag && (y > 0))
                                            {
                                                goto Label_0132;
                                            }
                                            continue;
                                        Label_0241:
                                            num13++;
                                            for (int num18 = x; !flag && (num18 <= num9); num18++)
                                            {
                                                for (int num19 = z; num19 <= num11; num19++)
                                                {
                                                    if ((flagArray[num18, num13, num19, m] || this.Voxels[num18, num13, num19].IsEmpty) || !this.Voxels[num18, num13, num19].Visible[m])
                                                    {
                                                        flag = true;
                                                        break;
                                                    }
                                                }
                                            }
                                            if (!flag)
                                            {
                                                num10 = num13;
                                                for (int num20 = x; num20 <= num9; num20++)
                                                {
                                                    for (int num21 = z; num21 <= num11; num21++)
                                                    {
                                                        if (!flagArray[num20, num13, num21, m])
                                                        {
                                                            flagArray[num20, num13, num21, m] = true;
                                                            num--;
                                                        }
                                                    }
                                                }
                                            }
                                        Label_0333:
                                            if (!flag && (num10 < (this.SizeY - 1)))
                                            {
                                                goto Label_0241;
                                            }
                                            continue;
                                        Label_0357:
                                            num13--;
                                            for (int num22 = y; !flag && (num22 <= num10); num22++)
                                            {
                                                for (int num23 = z; num23 <= num11; num23++)
                                                {
                                                    if ((flagArray[num13, num22, num23, m] || this.Voxels[num13, num22, num23].IsEmpty) || !this.Voxels[num13, num22, num23].Visible[m])
                                                    {
                                                        flag = true;
                                                        break;
                                                    }
                                                }
                                            }
                                            if (!flag)
                                            {
                                                x = num13;
                                                for (int num24 = y; num24 <= num10; num24++)
                                                {
                                                    for (int num25 = z; num25 <= num11; num25++)
                                                    {
                                                        if (!flagArray[num13, num24, num25, m])
                                                        {
                                                            flagArray[num13, num24, num25, m] = true;
                                                            num--;
                                                        }
                                                    }
                                                }
                                            }
                                        Label_0449:
                                            if (!flag && (x > 0))
                                            {
                                                goto Label_0357;
                                            }
                                            continue;
                                        Label_0466:
                                            num13++;
                                            for (int num26 = y; !flag && (num26 <= num10); num26++)
                                            {
                                                for (int num27 = z; num27 <= num11; num27++)
                                                {
                                                    if ((flagArray[num13, num26, num27, m] || this.Voxels[num13, num26, num27].IsEmpty) || !this.Voxels[num13, num26, num27].Visible[m])
                                                    {
                                                        flag = true;
                                                        break;
                                                    }
                                                }
                                            }
                                            if (!flag)
                                            {
                                                num9 = num13;
                                                for (int num28 = y; num28 <= num10; num28++)
                                                {
                                                    for (int num29 = z; num29 <= num11; num29++)
                                                    {
                                                        if (!flagArray[num13, num28, num29, m])
                                                        {
                                                            flagArray[num13, num28, num29, m] = true;
                                                            num--;
                                                        }
                                                    }
                                                }
                                            }
                                        Label_0558:
                                            if (!flag && (num9 < (this.SizeX - 1)))
                                            {
                                                goto Label_0466;
                                            }
                                            continue;
                                        Label_057C:
                                            num13++;
                                            for (int num30 = x; !flag && (num30 <= num9); num30++)
                                            {
                                                for (int num31 = y; num31 <= num10; num31++)
                                                {
                                                    if ((flagArray[num30, num31, num13, m] || this.Voxels[num30, num31, num13].IsEmpty) || !this.Voxels[num30, num31, num13].Visible[m])
                                                    {
                                                        flag = true;
                                                        break;
                                                    }
                                                }
                                            }
                                            if (!flag)
                                            {
                                                num11 = num13;
                                                for (int num32 = x; num32 <= num9; num32++)
                                                {
                                                    for (int num33 = y; num33 <= num10; num33++)
                                                    {
                                                        if (!flagArray[num32, num33, num13, m])
                                                        {
                                                            flagArray[num32, num33, num13, m] = true;
                                                            num--;
                                                        }
                                                    }
                                                }
                                            }
                                        Label_066E:
                                            if (!flag && (num11 < (this.SizeZ - 1)))
                                            {
                                                goto Label_057C;
                                            }
                                            continue;
                                        Label_0692:
                                            num13--;
                                            for (int num34 = x; !flag && (num34 <= num9); num34++)
                                            {
                                                for (int num35 = y; num35 <= num10; num35++)
                                                {
                                                    if ((flagArray[num34, num35, num13, m] || this.Voxels[num34, num35, num13].IsEmpty) || !this.Voxels[num34, num35, num13].Visible[m])
                                                    {
                                                        flag = true;
                                                        break;
                                                    }
                                                }
                                            }
                                            if (!flag)
                                            {
                                                z = num13;
                                                for (int num36 = x; num36 <= num9; num36++)
                                                {
                                                    for (int num37 = y; num37 <= num10; num37++)
                                                    {
                                                        if (!flagArray[num36, num37, num13, m])
                                                        {
                                                            flagArray[num36, num37, num13, m] = true;
                                                            num--;
                                                        }
                                                    }
                                                }
                                            }
                                        Label_0784:
                                            if (!flag && (z > 0))
                                            {
                                                goto Label_0692;
                                            }
                                        }
                                        this.VoxelFaces.Add(new VoxelFace(x, y, z, ((m != 4) && (m != 5)) ? ((num9 - x) + 1) : ((num10 - y) + 1), ((m != 0) && (m != 1)) ? ((num11 - z) + 1) : ((num10 - y) + 1), (Direction) m));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        private void InitVoxels(VoxData voxelData, float scale, Vector3 pivot)
        {
            this.Scale = scale;
            this.Pivot = pivot;
            this.SizeX = voxelData.SizeX;
            this.SizeY = voxelData.SizeY;
            this.SizeZ = voxelData.SizeZ;
            this.MainVoxelData = voxelData;
            this.Voxels = new Voxel[this.SizeX, this.SizeY, this.SizeZ];
            for (int i = 0; i < this.SizeX; i++)
            {
                for (int j = 0; j < this.SizeY; j++)
                {
                    for (int k = 0; k < this.SizeZ; k++)
                    {
                        this.Voxels[i, j, k].Init();
                        this.Voxels[i, j, k].ColorIndex = this.MainVoxelData.Voxels[i, j, k];
                    }
                }
            }
        }
    }
}

